{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cb354baf",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-1/router.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239412-lesson-5-router)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "ce6fff79-25b5-4884-8aaa-e3ebb7ddd549",
   "metadata": {},
   "source": [
    "# Router\n",
    "\n",
    "## Review\n",
    "\n",
    "We built a graph that uses `messages` as state and a chat model with bound tools.\n",
    "\n",
    "We saw that the graph can:\n",
    "\n",
    "* Return a tool call\n",
    "* Return a natural language response\n",
    "\n",
    "## Goals\n",
    "\n",
    "We can think of this as a router, where the chat model routes between a direct response or a tool call based upon the user input.\n",
    "\n",
    "This is a simple example of an agent, where the LLM is directing the control flow either by calling a tool or just responding directly. \n",
    "\n",
    "![Screenshot 2024-08-21 at 9.24.09 AM.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbac6543c3d4df239a4ed1_router1.png)\n",
    "\n",
    "Let's extend our graph to work with either output! \n",
    "\n",
    "For this, we can use two ideas:\n",
    "\n",
    "(1) Add a node that will call our tool.\n",
    "\n",
    "(2) Add a conditional edge that will look at the chat model output, and route to our tool calling node or simply end if no tool call is performed. \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ebb4fc6e-7c85-4fc8-a4a9-0c7a527c4e5b",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install --quiet -U langchain_openai langchain_core langgraph langgraph-prebuilt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "885e92d9",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, getpass\n",
    "\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"OPENAI_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "e3ba4df4-3045-49b1-9299-ced1fce14d24",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "def multiply(a: int, b: int) -> int:\n",
    "    \"\"\"Multiply a and b.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a * b\n",
    "\n",
    "llm = ChatOpenAI(model=\"gpt-4o\")\n",
    "llm_with_tools = llm.bind_tools([multiply])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c77555a2",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    " We use the  [built-in `ToolNode`](https://langchain-ai.github.io/langgraph/reference/agents/#langgraph.prebuilt.tool_node.ToolNode) and simply pass a list of our tools to initialize it. \n",
    " \n",
    " We use the [built-in `tools_condition`](https://langchain-ai.github.io/langgraph/reference/agents/#langgraph.prebuilt.tool_node.tools_condition) as our conditional edge."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9a6fde4e-cceb-4426-b770-97ee4b41e9da",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "from langgraph.graph import StateGraph, START, END\n",
    "from langgraph.graph import MessagesState\n",
    "from langgraph.prebuilt import ToolNode\n",
    "from langgraph.prebuilt import tools_condition\n",
    "\n",
    "# Node\n",
    "def tool_calling_llm(state: MessagesState):\n",
    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
    "\n",
    "# Build graph\n",
    "builder = StateGraph(MessagesState)\n",
    "builder.add_node(\"tool_calling_llm\", tool_calling_llm)\n",
    "builder.add_node(\"tools\", ToolNode([multiply]))\n",
    "builder.add_edge(START, \"tool_calling_llm\")\n",
    "builder.add_conditional_edges(\n",
    "    \"tool_calling_llm\",\n",
    "    # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
    "    # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
    "    tools_condition,\n",
    ")\n",
    "builder.add_edge(\"tools\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "# View\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "11b608c5-0c15-4fb7-aa24-80ce5774fb85",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Hello world.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "Hello! How can I assist you today?\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.messages import HumanMessage\n",
    "messages = [HumanMessage(content=\"Hello, what is 2 multiplied by 2?\")]\n",
    "messages = graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c08f20d8-f18f-4f62-8277-55fa5acb4477",
   "metadata": {},
   "source": [
    "Now, we can see that the graph runs the tool!\n",
    "\n",
    "It responds with a `ToolMessage`. "
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "34708377-16b6-4474-9e23-71890c1fb36e",
   "metadata": {},
   "source": [
    "## Studio\n",
    "\n",
    "**⚠️ Notice**\n",
    "\n",
    "Since filming these videos, we've updated Studio so that it can now be run locally and accessed through your browser. This is the preferred way to run Studio instead of using the Desktop App shown in the video. It is now called _LangSmith Studio_ instead of _LangGraph Studio_. Detailed setup instructions are available in the \"Getting Setup\" guide at the start of the course. You can find a description of Studio [here](https://docs.langchain.com/langsmith/studio), and specific details for local deployment [here](https://docs.langchain.com/langsmith/quick-start-studio#local-development-server).  \n",
    "To start the local development server, run the following command in your terminal in the `/studio` directory in this module:\n",
    "\n",
    "```\n",
    "langgraph dev\n",
    "```\n",
    "\n",
    "You should see the following output:\n",
    "```\n",
    "- 🚀 API: http://127.0.0.1:2024\n",
    "- 🎨 Studio UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024\n",
    "- 📚 API Docs: http://127.0.0.1:2024/docs\n",
    "```\n",
    "\n",
    "Open your browser and navigate to the Studio UI shown above.\n",
    "Load the `router` in Studio, which uses `module-1/studio/router.py` set in `module-1/studio/langgraph.json`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "43782c33-0f41-47f2-ae38-ddb2cd4ba6f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "if 'google.colab' in str(get_ipython()):\n",
    "    raise Exception(\"Unfortunately LangGraph Studio is currently not supported on Google Colab\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94928b21",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
